package top.huashengshu.geekbang.http;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import top.huashengshu.common.HttpDownloadUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class GeekBangHttpUtils {

    public static List<String> cookies;
    public static String cookieFilePath = "src/main/resources/static/geekbang-cookie.txt";

    public static JSONObject callApiByCookieFile(String referUrl, JSONObject requestBody) throws IOException {
        return callApiByCookieFile(referUrl, cookieFilePath, requestBody);
    }

    public static JSONObject callApiByCookieFile(String referUrl, String cookiePath, JSONObject requestBody) throws IOException {
        String cookieString = Files.readString(Path.of(cookiePath)).trim();
        return callApi(referUrl, cookieString, requestBody);
    }

    public static JSONObject callApi(String referUrl, JSONObject requestBody) throws IOException {
        return callApiByCookieFile(referUrl, requestBody);
    }

    public static JSONObject callApi(String referUrl, String cookieString, JSONObject requestBody) throws IOException {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        if (cookies == null || cookies.size() == 0) {
            cookies = new ArrayList<>(Arrays.asList(cookieString.split(";")));
        }
        // 将cookie存入头部
        headers.put(HttpHeaders.COOKIE, cookies);
        // headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("Host", "b.geekbang.org");
        headers.add("Origin", "https://b.geekbang.org");
        //headers.add("Referer", referUrl);
        // 设置请求参数和cookie
        HttpEntity<Object> httpEntity = new HttpEntity<>(requestBody.toJSONString(), headers);

        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        CloseableHttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();
        httpRequestFactory.setHttpClient(httpClient);
        restTemplate.setRequestFactory(httpRequestFactory);
        ResponseEntity<String> response = restTemplate.exchange(referUrl, HttpMethod.POST, httpEntity, String.class);
        List<String> newCookieList = response.getHeaders().get("Set-Cookie");
        if (newCookieList != null) {
            // source
            Map<String, String> cookieMap = cookies.stream().collect(Collectors.toMap(s -> s.split("=")[0], s -> s.split("=")[1]));
            newCookieList.forEach(str -> {
                        String cookie = str.split(";")[0];
                        String key = cookie.split("=")[0];
                        String val = cookie.split("=")[1];
                        cookieMap.put(key, val);
                    }
            );
            cookies = cookieMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.toList());
            Files.writeString(Path.of(cookieFilePath), String.join(";", cookies));
        }
        return JSONObject.parseObject(response.getBody());
    }


    public static String getArticleId(String url) throws Exception {
        Pattern pattern = Pattern.compile("detail/([0-9]*)/{0,1}.*");
        Matcher matcher = pattern.matcher(url);
        String id;
        if (matcher.find()) {
            id = matcher.group(1);
        } else {
            throw new Exception("no id: " + url);
        }
        return id;
    }

    public static JSONObject getCourseDetail(String articleId) throws IOException {
        JSONObject requestBody = new JSONObject();
        requestBody.put("article_id", articleId);
        return callApi("https://b.geekbang.org/app/v1/article/detail", requestBody);
    }

    public static JSONObject getArticles(Long pid) throws IOException {
        JSONObject requestBody = new JSONObject();
        requestBody.put("id", pid);
        return callApi("https://b.geekbang.org/app/v1/course/articles", requestBody);
    }

    /**
     * 创建目录：如果不存在则创建然后返回true，如果存在直接返回true
     *
     * @param destDirName 目录名全路径 盘符驱动+路径
     * @return true表示创建成功
     */
    public static boolean createDirect(String destDirName) {
        File file = new File(destDirName);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        return true;
    }


    public static boolean downloadFile(String url, String savePath) throws IOException {
        String cookieString = Files.readString(Path.of(cookieFilePath)).trim();
        return downloadFile(url, cookies == null ? cookieString : String.join(";", cookies), savePath);
    }

    public static boolean downloadFile(String url, String cookieString, String savePath) throws IOException {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        if (cookies == null || cookies.size() == 0) {
            cookies = new ArrayList<>(Arrays.asList(cookieString.split(";")));
        }
        // 将cookie存入头部
        headers.put(HttpHeaders.COOKIE, cookies);
        headers.add("authority", "static001.geekbang.org");
        headers.add("accept-encoding", "gzip, deflate, br, zstd");
        // 设置请求参数和cookie
        HttpEntity<Object> httpEntity = new HttpEntity<>(headers);

        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        CloseableHttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();
        httpRequestFactory.setHttpClient(httpClient);
        restTemplate.setRequestFactory(httpRequestFactory);
        ResponseEntity<Resource> response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Resource.class);
        List<String> newCookieList = response.getHeaders().get("Set-Cookie");
        if (newCookieList != null) {
            // source
            Map<String, String> cookieMap = cookies.stream().collect(Collectors.toMap(s -> s.split("=")[0], s -> s.split("=")[1]));
            newCookieList.forEach(str -> {
                        String cookie = str.split(";")[0];
                        String key = cookie.split("=")[0];
                        String val = cookie.split("=")[1];
                        cookieMap.put(key, val);
                    }
            );
            cookies = cookieMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.toList());
            Files.writeString(Path.of(cookieFilePath), String.join(";", cookies));
        }
        try (InputStream is = response.getBody().getInputStream()) {//java9新特性自动关闭流
            boolean flag = createDirect(savePath);
            if (flag) {
                try (FileOutputStream fos = new FileOutputStream(savePath);) {
                    is.transferTo(fos);//写入输出流
                    System.out.println("success\t=>\t" + savePath);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            downloadFile(url, cookieString, savePath);//异常则进行重新下载
        }
        return true;
    }
}
